package com.yunchao.library.socket.utils

import com.yunchao.library.socket.extensions.hexString
import timber.log.Timber
import java.security.MessageDigest
import java.security.NoSuchAlgorithmException
import javax.crypto.Cipher
import javax.crypto.SecretKey
import javax.crypto.SecretKeyFactory
import javax.crypto.spec.DESKeySpec
import javax.crypto.spec.IvParameterSpec
import javax.crypto.spec.SecretKeySpec


object EncryptUtils {

    /**
    * 使用 SHA-1 算法对数据进行哈希计算
    *
    * @param data 要哈希的字节数组
    * @return 20字节的 SHA-1 哈希结果
    * @throws IllegalArgumentException 如果输入数据为空
    * @throws SecurityException 如果 SHA-1 算法不可用（理论上不会发生，因为 Android 必须支持 SHA-1）
    */
    @Throws(SecurityException::class)
    fun encryptSHA1(data: ByteArray): ByteArray {
        require(data.isNotEmpty()) { "输入数据不能为空" }

        // 使用单例 MessageDigest 实例（线程安全）
        val digest = try {
            MessageDigest.getInstance("SHA-1").apply {
                update(data)
            }
        } catch (e: NoSuchAlgorithmException) {
            // 根据规范，SHA-1 是必须支持的算法，所以这里理论上不会发生
            throw SecurityException("SHA-1 算法不可用", e)
        }

        return digest.digest().also { result ->

            require(result.size == 20) {
                "SHA-1 哈希结果长度异常: 预期20字节，实际${result.size}字节"
            }

            Timber.e("SHA1-Result: ${result.hexString}")
        }
    }


    /**
     * 使用3DES算法加密数据 (CBC模式，PKCS7Padding)
     */
    fun encrypt3DES(
        data: ByteArray,
        key: ByteArray,
        transformation: String = "DESede/CBC/PKCS7Padding",
        iv: ByteArray = ByteArray(8) { 0 }
    ): ByteArray? {
        return symmetricTemplate(data, key, "DESede", transformation, iv, true)
    }

    /**
     * 使用3DES算法解密数据 (CBC模式，PKCS7Padding)
     */
    fun decrypt3DES(
        data: ByteArray,
        key: ByteArray,
        transformation: String = "DESede/CBC/PKCS7Padding",
        iv: ByteArray = ByteArray(8) { 0 }
    ): ByteArray? {
        return symmetricTemplate(data, key, "DESede", transformation, iv, false)
    }

    /**
     * 3DES算法计算MAC (ISO 9797-1 算法3)
     */
    fun calculateMac(data: ByteArray, key: ByteArray): ByteArray? {
        if (key.size != 16) return null
        return try {
            val cipher = Cipher.getInstance("DESede/CBC/PKCS7Padding")
            val iv = ByteArray(8) { 0 } // 初始向量为0
            val secretKey = generateTripleDesKey(key)
            cipher.init(Cipher.ENCRYPT_MODE, secretKey, IvParameterSpec(iv))

            val encrypted = cipher.doFinal(data) // 自动处理填充
            val lastBlockStart = encrypted.size - 8
            if (lastBlockStart < 0) return null

            encrypted.copyOfRange(lastBlockStart, lastBlockStart + 4) // 取最后块的前4字节
        } catch (e: Exception) {
            e.printStackTrace()
            null
        }
    }


    /**
     * 生成3DES密钥 (使用16字节密钥)
     */
    private fun generateTripleDesKey(keyBytes: ByteArray): SecretKey {
        val keyMaterial = ByteArray(24)
        System.arraycopy(keyBytes, 0, keyMaterial, 0, 16)
        System.arraycopy(keyBytes, 0, keyMaterial, 16, 8)
        return SecretKeySpec(keyMaterial, "DESede")
    }

    /**
     * 对称加密/解密工具方法
     */
    private fun symmetricTemplate(
        data: ByteArray,
        key: ByteArray,
        algorithm: String,
        transformation: String,
        iv: ByteArray?,
        isEncrypt: Boolean
    ): ByteArray? {
        if (data.isEmpty() || key.isEmpty() || (iv != null && iv.size != 8)) return null
        return try {
            val secretKey = when (algorithm) {
                "DES" -> {
                    val desKey = DESKeySpec(key)
                    val keyFactory = SecretKeyFactory.getInstance(algorithm)
                    keyFactory.generateSecret(desKey)
                }

                else -> SecretKeySpec(key, algorithm)
            }

            val cipher = Cipher.getInstance(transformation)
            if (iv == null || iv.isEmpty()) {
                cipher.init(if (isEncrypt) Cipher.ENCRYPT_MODE else Cipher.DECRYPT_MODE, secretKey)
            } else {
                val params = IvParameterSpec(iv)
                cipher.init(
                    if (isEncrypt) Cipher.ENCRYPT_MODE else Cipher.DECRYPT_MODE,
                    secretKey,
                    params
                )
            }
            cipher.doFinal(data)
        } catch (e: Exception) {
            e.printStackTrace()
            null
        }
    }
}